package com.education.ai.util;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceUtils;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Timestamp;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Function;

/**
 * JDBC操作工具类
 * 提供简化的JDBC操作方法
 */
@Component
public class JdbcUtil {

    private static final Logger logger = LoggerFactory.getLogger(JdbcUtil.class);

    @Autowired
    private JdbcTemplate jdbcTemplate;
    
    @Autowired
    private DataSource dataSource;

    /**
     * 执行查询操作
     *
     * @param sql SQL语句
     * @param args 查询参数
     * @return 查询结果列表
     */
    public List<Map<String, Object>> executeQuery(String sql, Object... args) {
        try {
            logger.debug("执行SQL查询: {}", sql);
            return jdbcTemplate.queryForList(sql, args);
        } catch (DataAccessException e) {
            logger.error("执行SQL查询出错: {}", sql, e);
            return new ArrayList<>();
        }
    }

    /**
     * 执行更新操作（INSERT、UPDATE、DELETE）
     *
     * @param sql SQL语句
     * @param args 更新参数
     * @return 受影响的行数
     * @throws RuntimeException 当执行出错时抛出异常
     */
    public int executeUpdate(String sql, Object... args) {
        try {
            logger.debug("执行SQL更新: {}", sql);
            int rows = jdbcTemplate.update(sql, args);
            if (rows <= 0) {
                logger.warn("SQL更新未影响任何行: {}", sql);
            }
            return rows;
        } catch (DataAccessException e) {
            logger.error("执行SQL更新出错: {}", sql, e);
            throw new RuntimeException("数据库更新操作失败: " + e.getMessage(), e);
        }
    }

    /**
     * 执行插入操作并返回生成的主键
     *
     * @param sql SQL语句
     * @param args 插入参数
     * @return 生成的主键值
     */
    public long executeInsert(String sql, Object... args) {
        try {
            logger.debug("执行SQL插入: {}", sql);
            
            // 记录所有参数
            StringBuilder params = new StringBuilder();
            for (int i = 0; i < args.length; i++) {
                params.append("参数").append(i + 1).append("=").append(args[i]).append(", ");
            }
            logger.debug("SQL参数: {}", params.toString());
            
            KeyHolder keyHolder = new GeneratedKeyHolder();

            jdbcTemplate.update(connection -> {
                PreparedStatement ps = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
                for (int i = 0; i < args.length; i++) {
                    // 处理参数
                    Object value = args[i];
                    if (value == null) {
                        logger.warn("参数{}为null，设置为null", i + 1);
                        ps.setObject(i + 1, null);
                    } else if (value instanceof String && ((String) value).isEmpty()) {
                        // 对于空字符串，特别是可能用于datetime字段的值，设置为null
                        logger.warn("参数{}为空字符串，设置为null", i + 1);
                        ps.setObject(i + 1, null);
                    } else {
                        ps.setObject(i + 1, value);
                    }
                }
                return ps;
            }, keyHolder);

            if (keyHolder.getKeys() != null && !keyHolder.getKeys().isEmpty()) {
                Number id = (Number) keyHolder.getKeys().get("id");
                if (id != null) {
                    return id.longValue();
                } else {
                    logger.warn("未获取到id字段，尝试获取自增主键");
                    return keyHolder.getKey() != null ? keyHolder.getKey().longValue() : -1L;
                }
            } else if (keyHolder.getKey() != null) {
                return keyHolder.getKey().longValue();
            } else {
                logger.warn("未获取到任何主键");
                return -1L;
            }
        } catch (DataAccessException e) {
            logger.error("执行SQL插入出错: {}", sql, e);
            return -1L;
        } catch (Exception e) {
            logger.error("执行SQL插入时发生未知错误: {}", e.getMessage(), e);
            return -1L;
        }
    }

    /**
     * 执行批量更新操作
     *
     * @param sql SQL语句
     * @param batchArgs 批量参数列表
     * @return 每个批次受影响的行数数组
     */
    public int[] executeBatch(String sql, List<Object[]> batchArgs) {
        try {
            logger.debug("执行SQL批量更新: {}", sql);
            return jdbcTemplate.batchUpdate(sql, batchArgs);
        } catch (DataAccessException e) {
            logger.error("执行SQL批量更新出错: {}", sql, e);
            return new int[0];
        }
    }

    /**
     * 批量更新带有自定义设置的SQL
     *
     * @param sql SQL语句
     * @param items 数据项列表
     * @param pss 自定义参数设置
     * @param <T> 数据项类型
     * @return 每个批次受影响的行数数组
     */
    public <T> int[] executeBatch(String sql, List<T> items, BatchPreparedStatementSetter pss) {
        try {
            logger.debug("执行SQL批量更新: {}", sql);
            return jdbcTemplate.batchUpdate(sql, pss);
        } catch (DataAccessException e) {
            logger.error("执行SQL批量更新出错: {}", sql, e);
            return new int[0];
        }
    }

    /**
     * 在事务中执行操作
     *
     * @param action 要执行的操作
     */
    @Transactional
    public void executeInTransaction(Runnable action) {
        try {
            action.run();
        } catch (Exception e) {
            logger.error("事务执行失败", e);
            throw new RuntimeException("事务执行失败: " + e.getMessage(), e);
        }
    }

    /**
     * 在事务中执行操作，并返回结果
     *
     * @param action 要执行的操作
     * @param <T> 结果类型
     * @return 操作返回的结果
     */
    @Transactional
    public <T> T executeInTransaction(java.util.function.Supplier<T> action) {
        try {
            return action.get();
        } catch (Exception e) {
            logger.error("事务执行失败", e);
            throw new RuntimeException("事务执行失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 在事务中执行操作，使用提供的Connection
     *
     * @param action 要执行的操作，接收Connection参数并返回结果
     * @param <T> 结果类型
     * @return 操作返回的结果
     */
    @Transactional
    public <T> T executeTransaction(Function<Connection, T> action) {
        Connection conn = null;
        try {
            conn = DataSourceUtils.getConnection(dataSource);
            // 确保使用Spring管理的连接，不要手动关闭它
            return action.apply(conn);
        } catch (Exception e) {
            logger.error("事务执行失败", e);
            throw new RuntimeException("事务执行失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 将各种时间类型转换为LocalDateTime
     * 
     * @param timeObj 时间对象
     * @return LocalDateTime对象
     */
    public LocalDateTime convertToLocalDateTime(Object timeObj) {
        if (timeObj == null) {
            return null;
        }
        
        if (timeObj instanceof LocalDateTime) {
            return (LocalDateTime) timeObj;
        }
        
        if (timeObj instanceof Timestamp) {
            return ((Timestamp) timeObj).toLocalDateTime();
        }
        
        if (timeObj instanceof Date) {
            Instant instant = ((Date) timeObj).toInstant();
            return LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
        }
        
        if (timeObj instanceof Long) {
            Instant instant = Instant.ofEpochMilli((Long) timeObj);
            return LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
        }
        
        if (timeObj instanceof String) {
            try {
                return LocalDateTime.parse((String) timeObj);
            } catch (Exception e) {
                logger.error("无法将字符串转换为LocalDateTime: {}", timeObj, e);
            }
        }
        
        logger.warn("无法转换为LocalDateTime的类型: {}", timeObj.getClass().getName());
        return null;
    }
} 